#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdint.h>
#include <sys/un.h>
#include "consola.h"

#define NSTRS       3           /* no. of strings  */
#define ADDRESS     "mysocket"  /* addr to connect */
void error(const char *);
void atenderConsola(void *arg)
{

   int32_t sockfd, newsockfd, servlen, nbytes;
   socklen_t clilen;
   struct sockaddr_un  cli_addr, serv_addr;

   stDatosHilo *datosHilo = (stDatosHilo *)arg;

   if ((sockfd = socket(AF_UNIX,SOCK_STREAM,0)) < 0)
       error("creating socket");
   bzero((char *) &serv_addr, sizeof(serv_addr));
   serv_addr.sun_family = AF_UNIX;
   strcpy(serv_addr.sun_path, ADDRESS);
   servlen=strlen(serv_addr.sun_path) +
                     sizeof(serv_addr.sun_family);
   unlink(ADDRESS);
   if(bind(sockfd,(struct sockaddr *)&serv_addr,servlen)<0)
       error("binding socket");

   listen(sockfd,5);
   clilen = sizeof(cli_addr);

   //FORK EXEC
  pid_t pid = fork();
  int32_t rval;
  if (pid == 0) {
		//if (execl((*datosHilo->pathConsola), "/home/utn_so/Escritorio/consolaPPD/ConsolaPPD/Debug/config.txt", (char*)0) == -1) {
	  if (execl((*datosHilo->pathConsola), (*datosHilo->configConsola), (char*)0) == -1) {
			perror("execv");
		}
  } else {
		//printf("Mi PID es %d y mi hijo es %d\n", getpid(), pid);
		//waitpid(pid, &rval, 0);
		//printf("La ejecucion de mi hijo termino con el siguiente valor: %d\n", rval);

  }
      //HASTA ACA ES FORK EXEC LO QUE NECESITAS

   newsockfd = accept(
        sockfd,(struct sockaddr *)&cli_addr,&clilen);
   if (newsockfd < 0)
        error("accepting");
   char *datos ;


   PAQUETE_NIPC_CABECERA *cabecera = (PAQUETE_NIPC_CABECERA *)malloc(sizeof(PAQUETE_NIPC_CABECERA));
   while(1){
	   nbytes = recv(newsockfd,cabecera,sizeof(PAQUETE_NIPC_CABECERA),MSG_WAITALL);
	   if (nbytes > 0)
	   {
		   switch (cabecera->type)
		   {
		   case consolaINFO:
			   pthread_mutex_lock(datosHilo->semaforo);
			   responderInfo((*(datosHilo->posicionActual)),newsockfd);
			   pthread_mutex_unlock(datosHilo->semaforo);
			   break;
		   case consolaTRACE:
			   datos = (char *)malloc(100);

			   nbytes = recv(newsockfd,datos,cabecera->payloadlength,MSG_WAITALL);
			   if (nbytes>0)
			   {
				   pthread_mutex_lock(datosHilo->semaforo);
				   crearPedidosTrace(newsockfd,datos,datosHilo->semaforo,
						   	   	   	 datosHilo->listaPedidos,datosHilo->listaEjecutar,
						   	   	   	 datosHilo->algoritmo,&datosHilo->agregadosEjecutar
						   	   	   	 ,datosHilo->listaSincro,&datosHilo->contadorEjecutar,
						   	   	   	 datosHilo->semaforoContador);


				   pthread_mutex_unlock(datosHilo->semaforo);
			   }

			   break;
		   case consolaCLEAN:
			   datos = (char *)malloc(100);

			   nbytes = recv(newsockfd,datos,cabecera->payloadlength,MSG_WAITALL);
			   if (nbytes>0)
			   {
				   pthread_mutex_lock(datosHilo->semaforo);
				   responderClean(datosHilo->pathFatFile,newsockfd,datos,
						   	   	  datosHilo->semaforo,datosHilo->listaPedidos,
						   	   	  datosHilo->algoritmo,datosHilo->listaEjecutar,
						   	   	  &datosHilo->agregadosEjecutar,datosHilo->listaSincro,
						   	   	  &datosHilo->contadorEjecutar,datosHilo->semaforoContador);
				   pthread_mutex_unlock(datosHilo->semaforo);
			   }
			   free(datos);
			   break;
		   default:
			   break;
		   }
	   }
   }
   close(newsockfd);
   close(sockfd);

   return;
}

void error(const char *msg)
{
    perror(msg);
    exit(0);
}

void responderInfo(chs *posActual,int32_t socket)
{
	char *mensaje = (char *)malloc(100);
	char *conversion = malloc(sizeof(char)*20);

	strcpy(mensaje,"la posicion actual es c:");

    sprintf(conversion, "%d", posActual->c);
    strcat(mensaje,conversion);

    strcat(mensaje," h: ");
    sprintf(conversion, "%d", posActual->h);
    strcat(mensaje,conversion);

    strcat(mensaje," s: ");
    sprintf(conversion, "%d", posActual->s);
    strcat(mensaje,conversion);
    strcat(mensaje,"\0");
    int payLoadLength = strlen(mensaje) + 1;

	char *paquetito;
	paquetito = serializarNipc(consolaINFO,mensaje,payLoadLength);

	send(socket,paquetito,payLoadLength + sizeof(PAQUETE_NIPC_CABECERA),0);

	free(conversion);
	free(mensaje);
	free(paquetito);
}

void crearPedidosTrace(int32_t socket,char *datos,pthread_mutex_t *semaforo,
					   stNodoPedido **listaPedidos,stNodoPedido **listaEjecutar,
					   char **algoritmo,int32_t *agregadosEjecutar, stNodoSincro **listaSincro,
					   int32_t *contadorEjecutar,sem_t *semaforoContador)
{
	char *dir = strtok(datos,"-");

	stPedido *pedido = malloc(sizeof(stPedido));
	pedido->sector = atol(dir);
	pedido->socketPFS = socket;
	pedido->tipoOperacion = TRACE;

	AgregarPedido(listaPedidos,pedido,algoritmo,agregadosEjecutar,
			listaEjecutar,listaSincro,contadorEjecutar,semaforoContador);


	while((dir=strtok(NULL,"-")) != NULL)
	{
		pedido = malloc(sizeof(stPedido));
		pedido->sector = atol(dir);
		pedido->socketPFS = socket;
		pedido->tipoOperacion = TRACE;

		AgregarPedido(listaPedidos,pedido,algoritmo,agregadosEjecutar,
				listaEjecutar,listaSincro,contadorEjecutar,semaforoContador);
	}
}

void responderClean(char **pathFatFile,int32_t socket,char *datos,
		pthread_mutex_t *semaforo, stNodoPedido **listaPedidos,
		char **algoritmo, stNodoPedido **listaEjecutar, int32_t *agregadosEjecutar,
		stNodoSincro **listaSincro, int32_t *contadorEjecutar,sem_t *semaforoContador)
{
	int32_t desde,hasta;

	//preparo respuesta antes del strtok
	char *mensaje = malloc(60);
	strcpy(mensaje,"todos los sectores entre ");
	strcat(mensaje,datos);
	strcat(mensaje," han sido limpiados");
	strcat(mensaje,"\0");

	char *dir= strtok(datos,"-");
	desde = atoi(dir);
	dir= strtok(NULL,"-");
	hasta = atoi(dir);

	hasta ++;
	stPedido *pedido;
	for(;desde<hasta;desde++)
	{
		pedido = malloc(sizeof(stPedido));
		pedido->tipoOperacion = ESCRIBIR;
		pedido->sector = desde;
		strcpy(pedido->contenido,"\0");

		AgregarPedido(listaPedidos,pedido,algoritmo,agregadosEjecutar,
				listaEjecutar,listaSincro,contadorEjecutar,semaforoContador);



	}
	free(pedido);


	int payLoadLength = strlen(mensaje) +1;
	char *paquetito;
	paquetito = serializarNipc(consolaINFO,mensaje,payLoadLength);

	send(socket,paquetito,payLoadLength + sizeof(PAQUETE_NIPC_CABECERA),0);
}
